/*
 *  (c) 2015 fullhan.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

/*****************************************************************************
 *  Include Section
 *  add all #include here
 *****************************************************************************/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <malloc.h>
#include <sdhci.h>
#include <asm/arch/hardware.h>
#include <mmc.h> 
#include <fh_mshc_lite.h>
#include <fh_mshc_lite_dll.h>
/*****************************************************************************
 * Define section
 * add all #define here
 *****************************************************************************/
#define TUING_TIMEOUT	1000
#define SDHCI_CMD_MAX_TIMEOUT			3200
#define SDHCI_CMD_DEFAULT_TIMEOUT		100
#define SDHCI_READ_STATUS_TIMEOUT		1000
#define DLL_TX_RXCMD_PASS_TIMES	10
#define DLL_RX_HS200_PASS_TIMES	10
#define DLL_RX_HS400_PASS_TIMES	10
#define DLL_TX_HS400_PASS_TIMES	10

#define DLL_HS_CLASSIC_PASS_TIMES	2
/****************************************************************************
 * ADT section
 *  add definition of user defined Data Type that only be used in this file  here
 ***************************************************************************/




/*****************************************************************************
 *  static fun;
 *****************************************************************************/
static int mmc_tuning_common_init(struct mmc *mmc, u8 *p_u8_extdata);
static void mmc_printf_dl(u8 p_buf[][MAX_RX_DELAY_LINE_SIZE], u32 accuracy);
static void dump_ext_buf(u8 *p_8, u32 size);
static int mmc_tuning_get_ext_csd_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs200_tx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs200_rx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs200_rx_data_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs200_fix_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs400_es_rx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs400_es_rxdata_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs400_es_txdata_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs400_es_fix_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs400_classic_rx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs400_classic_rxdata_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs400_classic_txdata_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static int mmc_hs400_classic_fix_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
static void init_tx_tuning_data(u8* tx_data, u32 tx_size);
static int mmc_random_fix_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
//static void dump_dl_rec_list(struct rec_dl_info *p_info, int rec_dl_size);
static void sdhci_tuning_cmd_done(struct sdhci_host *host, struct mmc_cmd *cmd);
static void tuning_sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data);
static int tuning_sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
unsigned int start_addr);
static int sdhci_tuning_send_command(struct sdhci_host *host, struct mmc_cmd *cmd,
struct mmc_data *data);
static int mmc_tuning_send_status(struct sdhci_host *host, int timeout, int mmc_rca);
static int sdhci_card_busy(struct sdhci_host *host);
static int _mmc_tuning_switch(struct sdhci_host *host, u8 set,
u8 index, u8 value, bool send_status);
static int mmc_tuning_switch(struct sdhci_host *host, u8 set, u8 index, u8 value);
static int mmc_tuning_set_blocklen(struct sdhci_host *host, int len);
static int mmc_auto_tuning_common_init(struct sdhci_host *host, u8 *p_u8_extdata);
/*****************************************************************************
 *  extern fun;
 *****************************************************************************/
extern u8 g_mshc_ext_data[512];
extern int mmc_send_status(struct mmc *mmc, int timeout);
extern int ctrlc(void);
extern int mmc_set_blocklen(struct mmc *mmc, int len);
extern int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value);
extern int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data);
/*****************************************************************************
 * Global variables section - Local
 * define global variables(will be refered only in this file) here,
 * static keyword should be used to limit scope of local variable to this file
 * e.g.
 *  static uint8_t ufoo;
 *****************************************************************************/
u8 g_hs200_buf[0x80] = {0};
u8 g_cmp_csd[512] = {0};
u8 g_non_ds_ddr[MAX_TX_DELAY_LINE_SIZE][MAX_RX_DELAY_LINE_SIZE] = {0};
__attribute__((aligned(32))) static const u8 tuning_blk_pattern_8bit[] = {
	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
};

u32 auto_scan_mode_2_clk[AUTO_SCAN_END] = {
	52000000,
	200000000,
	200000000,
};

/*****************************************************************************
 * func below..
 *****************************************************************************/

void translate_mmcid_to_string(char *name, u32 *mmc_id){
	sprintf(name, "%c%c%c%c%c%c", mmc_id[0] & 0xff,
	(mmc_id[1] >> 24), (mmc_id[1] >> 16) & 0xff,
	(mmc_id[1] >> 8) & 0xff, mmc_id[1] & 0xff,
	(mmc_id[2] >> 24) & 0xff);
}

static int mmc_tuning_common_init(struct mmc *mmc, u8 *p_u8_extdata){

	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	u32 timing;
	u32 clk;
	int err;
	struct mmc_cmd cmd;
	struct mmc_data data = {0};
	u32 timeout = TUING_TIMEOUT;
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}

	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(!host || !p_mshc || !plat_info){
		printf("err got null info...\n");
		printf("host : p_mshc : plat_info = %x : %x : %x\n",
		(int)host, (int)p_mshc, (int)plat_info);
		return -2;
	}


	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_ENABLE);
	fh_mshc_tuning_ctrl_init(host);

	clk = 400000;
	timing = MMC_TIMING_MMC_HS;
	fh_mshc_tuning_set_clock(host, clk, timing, 1, EMMC_ES_MODE_DISABLE);
	cmd.cmdidx =  0;
	cmd.resp_type = MMC_RSP_NONE;
	cmd.cmdarg = 0;
	err = mmc_send_cmd(mmc, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}

	do{
		cmd.cmdidx = MMC_CMD_SEND_OP_COND;
		cmd.resp_type = MMC_RSP_R3;
		cmd.cmdarg = 0x40000080;
		mmc_send_cmd(mmc, &cmd, NULL);
		timeout--;
		if(!timeout)
			break;
		udelay(100);
	}while(!(cmd.response[0] & OCR_BUSY));
	if(!timeout){
		printf("try cmd1 timeout\n");
		return -3;
	}


	cmd.cmdidx =  2;
	cmd.resp_type = MMC_RSP_R2;
	cmd.cmdarg = 0;
	err = mmc_send_cmd(mmc, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}


	//set rel id
	cmd.cmdidx = 3;
	cmd.cmdarg = 1 << 16;
	cmd.resp_type = MMC_RSP_R6;
	err = mmc_send_cmd(mmc, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}


	/* Get the Card-Specific Data */
	cmd.cmdidx = 9;
	cmd.resp_type = MMC_RSP_R2;
	cmd.cmdarg = 1 << 16;
	err = mmc_send_cmd(mmc, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}
	//sel device..
	cmd.cmdidx = 7;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = 1 << 16;
	err = mmc_send_cmd(mmc, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}
	//dev is lock? cmd42 to unlock..

	//cmd8 to check if sup hs200..
	cmd.cmdidx = 8;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = 0;
	data.dest = (char *)p_u8_extdata;
	data.blocks = 1;
	data.blocksize = MMC_MAX_BLOCK_LEN;
	data.flags = MMC_DATA_READ;

	err = mmc_send_cmd(mmc, &cmd, &data);
	if (err){
		printf("!!!!!! raw cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}
	//swtich area....
	p_u8_extdata[EXT_CSD_PART_CONF] &= ~(PART_ACCESS_MASK);
	p_u8_extdata[EXT_CSD_PART_CONF] |= (CONFIG_AUTO_TUNING_EMMC_AREA & PART_ACCESS_MASK);
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_PART_CONF, p_u8_extdata[EXT_CSD_PART_CONF]);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}

	//reread extdata
	cmd.cmdidx = 8;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = 0;
	data.dest = (char *)p_u8_extdata;
	data.blocks = 1;
	data.blocksize = MMC_MAX_BLOCK_LEN;
	data.flags = MMC_DATA_READ;

	err = mmc_send_cmd(mmc, &cmd, &data);
	if (err){
		printf("!!!!!! fix cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}
	return 0;
}

static void mmc_printf_dl(u8 p_buf[][MAX_RX_DELAY_LINE_SIZE], u32 accuracy)
{
	u32 num;
	u32 tx, rx;

	printf("Row coordinates:RX\nColumn coordinates:TX\n");	

	printf("  ");
	for(num = 0; num < MAX_TX_DELAY_LINE_SIZE; num+=accuracy){
		printf("%2x",num);
	}
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += accuracy){
		printf("\n%2x",tx);
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += accuracy){
			if(p_buf[tx][rx] == 0){
				printf("  ");
			}else{
				printf("%2x",p_buf[tx][rx]);
			}
		}
	}
	printf("\n");
}


static void dump_ext_buf(u8 *p_8, u32 size){
	int i;
	for(i = 0; i < size;i++){
		if(i !=0 && i%16 == 0)
			printf("\n");
		if(i%4 == 0)
			printf("[%04d] :: ",i);
		printf("%02x ",p_8[i]);
	}
	printf("\n");
} 

static int mmc_tuning_get_ext_csd_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct mmc_cmd cmd;
	u8 *p_u8;
	struct mmc_data data = {0};

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	cmd.cmdidx = 8;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = 0;
	data.dest = (char *)g_mshc_ext_data;
	data.blocks = 1;
	data.blocksize = MMC_MAX_BLOCK_LEN;
	data.flags = MMC_DATA_READ;

	err = mmc_send_cmd(mmc, &cmd, &data);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return -1;
	}
	p_u8 = (u8 *)g_mshc_ext_data;
	dump_ext_buf(p_u8, MMC_MAX_BLOCK_LEN);
	dump_est_csd_reg(p_u8);
	return 0;
}

U_BOOT_CMD(
 mmc_tuning_get_ext_csd_reg, 4, 0, mmc_tuning_get_ext_csd_reg,
 "dump ext csd data",
 ""
);

static int mmc_hs200_tx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	int rx_cmd_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;
	int err;


	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}

	if(argc != 2){
		printf("mmc_hs200_tx_cmd_scan input parameter err, such as: rx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}

	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	rx_cmd_dll_val = simple_strtoul(argv[1], NULL, 16);
	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}


	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);
	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS200;
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx;
			dll.rxdata_dly = 0;
			dll.rxcmd_dly = rx_cmd_dll_val;
			fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = mmc_send_cmd(mmc, &cmd, NULL);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
			}
			else{
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;	
			}

			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_TX_RX_CMD;
			}
		}
	}

REPORT_RESULT_TX_RX_CMD:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs200_tx_cmd_scan, 4, 0, mmc_hs200_tx_cmd_scan,
 "scan corrected mmc hs200 tx cmd delay line settings",
 ""
);


static int mmc_hs_tx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	int rx_cmd_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;
	int err;


	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}

	if(argc != 2){
		printf("mmc_hs200_tx_cmd_scan input parameter err, such as: rx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}

	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	rx_cmd_dll_val = simple_strtoul(argv[1], NULL, 16);
	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}
	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);
	//switch ctrl width and timing
	clk = 52000000;
	timing = MMC_TIMING_MMC_HS;
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx;
			dll.rxdata_dly = 0;
			dll.rxcmd_dly = rx_cmd_dll_val;
			fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = mmc_send_cmd(mmc, &cmd, NULL);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
			}
			else{
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;	
			}

			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_TX_RX_CMD;
			}
		}
	}

REPORT_RESULT_TX_RX_CMD:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs_tx_cmd_scan, 4, 0, mmc_hs_tx_cmd_scan,
 "scan corrected mmc hs tx cmd delay line settings",
 ""
);



static int mmc_hs200_rx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	u32 tx_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;


	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}

	if(argc != 2){
		printf("mmc_hs200_rx_cmd_scan input parameter err, such as: tx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}

	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);
	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS200;
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			#if(0)
			phy_dly_setting(p_mshc, tx_dll_val, 0, rx);
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
			#endif
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx_dll_val;
			dll.rxdata_dly = 0;
			dll.rxcmd_dly = rx;
			fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = mmc_send_cmd(mmc, &cmd, NULL);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
			}
			else{
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;	
			}

			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_TX_RX_CMD;
			}
		}
	}

REPORT_RESULT_TX_RX_CMD:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs200_rx_cmd_scan, 4, 0, mmc_hs200_rx_cmd_scan,
 "scan corrected mmc hs200 rx cmd delay line settings",
 ""
);


static int mmc_hs_rx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	u32 tx_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;


	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}

	if(argc != 2){
		printf("mmc_hs200_rx_cmd_scan input parameter err, such as: tx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}

	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);
	//switch ctrl width and timing
	clk = 52000000;
	timing = MMC_TIMING_MMC_HS;
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			#if(0)
			phy_dly_setting(p_mshc, tx_dll_val, 0, rx);
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
			#endif
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx_dll_val;
			dll.rxdata_dly = 0;
			dll.rxcmd_dly = rx;
			fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = mmc_send_cmd(mmc, &cmd, NULL);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
			}
			else{
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;	
			}

			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_TX_RX_CMD;
			}
		}
	}

REPORT_RESULT_TX_RX_CMD:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs_rx_cmd_scan, 4, 0, mmc_hs_rx_cmd_scan,
 "scan corrected mmc hs rx cmd delay line settings",
 ""
);


static int mmc_hs200_rx_data_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	int rx_cmd_dll_val;
	u32 tx_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;
	struct mmc_data data = {0};

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}

	if(argc != 3){
		printf("mmc_hs200_rxdata_tuning_scan input parameter err, such as: tx_cmd_dl rx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}

	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_cmd_dll_val = simple_strtoul(argv[2], NULL, 16);
	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS200;

	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS200_RX;
			}
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx_dll_val;
			dll.rxdata_dly = rx;
			dll.rxcmd_dly = rx_cmd_dll_val;
			fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
			#if(0)
			phy_dly_setting(p_mshc, tx_dll_val, rx, rx_cmd_dll_val);
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
			#endif
			cmd.cmdidx = 21;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			//width 8 = 0x80 byte
			data.blocksize = 0x80;
			data.blocks = 1;
			data.flags = MMC_DATA_READ;
			data.dest = (char *)g_hs200_buf;
			memset(g_hs200_buf, 0xff, 0x80);
			err = mmc_send_cmd(mmc, &cmd, &data);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}

			if (memcmp((const void *)g_hs200_buf, tuning_blk_pattern_8bit, 0x80) == 0){
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}
		}
	}

REPORT_RESULT_HS200_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs200_rx_data_tuning_scan, 4, 0, mmc_hs200_rx_data_tuning_scan,
 "scan corrected mmc hs200 rx data line delay line settings",
 ""
);

static int mmc_hs_rx_data_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	int rx_cmd_dll_val;
	u32 tx_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;
	struct mmc_data data = {0};

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}

	if(argc != 3){
		printf("mmc_hs200_rxdata_tuning_scan input parameter err, such as: tx_cmd_dl rx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}

	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_cmd_dll_val = simple_strtoul(argv[2], NULL, 16);
	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

	//switch ctrl width and timing
	clk = 52000000;
	timing = MMC_TIMING_MMC_HS;

	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS200_RX;
			}
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx_dll_val;
			dll.rxdata_dly = rx;
			dll.rxcmd_dly = rx_cmd_dll_val;
			fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
			#if(0)
			phy_dly_setting(p_mshc, tx_dll_val, rx, rx_cmd_dll_val);
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
			#endif
			cmd.cmdidx = 8;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 0;
			data.dest = (char *)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = MMC_MAX_BLOCK_LEN;
			data.flags = MMC_DATA_READ;

			err = mmc_send_cmd(mmc, &cmd, &data);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				//continue;
			}
			else{
				printf("########pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}

		}
	}

REPORT_RESULT_HS200_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs_rx_data_tuning_scan, 4, 0, mmc_hs_rx_data_tuning_scan,
 "scan corrected mmc hs rx data line delay line settings",
 ""
);


static int mmc_hs200_fix_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	int rx_cmd_dll_val;
	u32 tx_dll_val;
	u32 rx_dll_val;	
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	struct mmc_data data = {0};


	if(argc != 4){
		printf("mmc_hs200_fix_test input parameter err, such as: tx_data_dl rx_cmd_dl rx_data_dl\n");
		return CMD_RET_FAILURE;
	}

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_cmd_dll_val = simple_strtoul(argv[2], NULL, 16);
	rx_dll_val = simple_strtoul(argv[3], NULL, 16);
	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	mmc_set_blocklen(mmc, 512);
	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS200;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

#if(0)
	phy_dly_setting(p_mshc, tx_dll_val, rx_dll_val, rx_cmd_dll_val);
	fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
#endif

	struct fh_mshc_phy_dll dll;
	dll.tx_dly = tx_dll_val;
	dll.rxdata_dly = rx_dll_val;
	dll.rxcmd_dly = rx_cmd_dll_val;
	fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS200_RX;
			}

			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
				//printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}
		}
	}

REPORT_RESULT_HS200_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs200_fix_test, 4, 0, mmc_hs200_fix_test,
 "final tx all tuning val..",
 ""
);

static int mmc_hs_fix_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	int rx_cmd_dll_val;
	u32 tx_dll_val;
	u32 rx_dll_val;	
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	struct mmc_data data = {0};


	if(argc != 4){
		printf("mmc_hs200_fix_test input parameter err, such as: tx_data_dl rx_cmd_dl rx_data_dl\n");
		return CMD_RET_FAILURE;
	}

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_cmd_dll_val = simple_strtoul(argv[2], NULL, 16);
	rx_dll_val = simple_strtoul(argv[3], NULL, 16);
	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	mmc_set_blocklen(mmc, 512);
	//switch ctrl width and timing
	clk = 52000000;
	timing = MMC_TIMING_MMC_HS;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

#if(0)
	phy_dly_setting(p_mshc, tx_dll_val, rx_dll_val, rx_cmd_dll_val);
	fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
#endif

	struct fh_mshc_phy_dll dll;
	dll.tx_dly = tx_dll_val;
	dll.rxdata_dly = rx_dll_val;
	dll.rxcmd_dly = rx_cmd_dll_val;
	fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS200_RX;
			}

			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
				//printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}
		}
	}

REPORT_RESULT_HS200_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs_fix_test, 4, 0, mmc_hs_fix_test,
 "final tx all tuning val..",
 ""
);

static int mmc_hs200_classic_tuning(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;

	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	struct mmc_data data = {0};


	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS200_RX;
			}
			//here add force reset emmc card..
			if(plat_info->soc_clk_init)
				plat_info->soc_clk_init(host);
			fh_mshc_lite_hw_reset(p_mshc);
			err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
			if(err){
				printf("mmc common init err..%x\n",err);
				return err;
			}

			//set width 8 bit
			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
				EXT_CSD_BUS_WIDTH, 2);
			if (err) {
				printf("switch width err, err:%d\n", err);
				return err;
			}
			//set hs200 timing and driver strength 0
			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
			if (err) {
				printf("switch timing err, err:%d\n", err);
				return err;
			}

			mmc_set_blocklen(mmc, 512);
			//switch ctrl width and timing
			clk = 200000000;
			timing = MMC_TIMING_MMC_HS200;

			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx;
			dll.rxdata_dly = rx;
			dll.rxcmd_dly = rx;
			fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
#if(0)
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);	
			phy_dly_setting(p_mshc, tx, rx, rx);
#endif
			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}
		}
	}

REPORT_RESULT_HS200_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs200_classic_tuning, 4, 0, mmc_hs200_classic_tuning,
 "classic tuning hs200..",
 ""
);



static int mmc_hs_classic_tuning(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;

	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	struct mmc_data data = {0};


	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS200_RX;
			}
			//here add force reset emmc card..
			if(plat_info->soc_clk_init)
				plat_info->soc_clk_init(host);
			fh_mshc_lite_hw_reset(p_mshc);
			err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
			if(err){
				printf("mmc common init err..%x\n",err);
				return err;
			}

			//set width 8 bit
			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
				EXT_CSD_BUS_WIDTH, 2);
			if (err) {
				printf("switch width err, err:%d\n", err);
				return err;
			}
			//set hs200 timing and driver strength 0
			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
			if (err) {
				printf("switch timing err, err:%d\n", err);
				return err;
			}

			mmc_set_blocklen(mmc, 512);
			//switch ctrl width and timing
			clk = 52000000;
			timing = MMC_TIMING_MMC_HS;

			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx;
			dll.rxdata_dly = rx;
			dll.rxcmd_dly = rx;
			fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
#if(0)
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);	
			phy_dly_setting(p_mshc, tx, rx, rx);
#endif
			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}
		}
	}

REPORT_RESULT_HS200_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs_classic_tuning, 4, 0, mmc_hs_classic_tuning,
 "classic tuning hs..",
 ""
);




static int mmc_hs200_classic_tuning_with_fix_rx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;

	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;
	u32 rx_init;

	struct mmc_data data = {0};


	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}


	if(argc != 2){
		printf("such as: rx_dl\n");
		return CMD_RET_FAILURE;
	}
	rx_init = simple_strtoul(argv[1], NULL, 16);

	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS200_RX;
			}
			//here add force reset emmc card..
			if(plat_info->soc_clk_init)
				plat_info->soc_clk_init(host);
			fh_mshc_lite_hw_reset(p_mshc);
			err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
			if(err){
				printf("mmc common init err..%x\n",err);
				return err;
			}

			//set width 8 bit
			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
				EXT_CSD_BUS_WIDTH, 2);
			if (err) {
				printf("switch width err, err:%d\n", err);
				return err;
			}
			//set hs200 timing and driver strength 0
			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
			if (err) {
				printf("switch timing err, err:%d\n", err);
				return err;
			}

			mmc_set_blocklen(mmc, 512);
			//switch ctrl width and timing
			clk = 200000000;
			timing = MMC_TIMING_MMC_HS200;

			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx;
			dll.rxdata_dly = rx_init;
			dll.rxcmd_dly = rx_init;
			fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
#if(0)
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);	
			phy_dly_setting(p_mshc, tx, rx, rx);
#endif
			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}
		}
	}

REPORT_RESULT_HS200_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs200_classic_tuning_with_fix_rx, 4, 0, mmc_hs200_classic_tuning_with_fix_rx,
 "classic tuning hs200..",
 ""
);




static int mmc_hs_classic_tuning_with_fix_rx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;

	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;
	u32 rx_init;

	struct mmc_data data = {0};


	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}


	if(argc != 2){
		printf("such as: rx_dl\n");
		return CMD_RET_FAILURE;
	}
	rx_init = simple_strtoul(argv[1], NULL, 16);

	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS200_RX;
			}
			//here add force reset emmc card..
			if(plat_info->soc_clk_init)
				plat_info->soc_clk_init(host);
			fh_mshc_lite_hw_reset(p_mshc);
			err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
			if(err){
				printf("mmc common init err..%x\n",err);
				return err;
			}

			//set width 8 bit
			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
				EXT_CSD_BUS_WIDTH, 2);
			if (err) {
				printf("switch width err, err:%d\n", err);
				return err;
			}
			//set hs200 timing and driver strength 0
			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
			if (err) {
				printf("switch timing err, err:%d\n", err);
				return err;
			}

			mmc_set_blocklen(mmc, 512);
			//switch ctrl width and timing
			clk = 52000000;
			timing = MMC_TIMING_MMC_HS;

			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx;
			dll.rxdata_dly = rx_init;
			dll.rxcmd_dly = rx_init;
			fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
#if(0)
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);	
			phy_dly_setting(p_mshc, tx, rx, rx);
#endif
			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}
		}
	}

REPORT_RESULT_HS200_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs_classic_tuning_with_fix_rx, 4, 0, mmc_hs_classic_tuning_with_fix_rx,
 "classic tuning hs..",
 ""
);



static int mmc_hs400_es_rx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	u32 tx_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(argc != 2){
		printf("mmc_hs400_rx_cmd_scan input parameter err, such as: tx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}
	tx_dll_val = simple_strtoul(argv[1], NULL, 16);

	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6 | (1 << 7));
	if (err) {
		printf("switch 8bit ddr err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS400_RX;
			}
			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);
			#if(0)
			phy_dly_setting(p_mshc, tx_dll_val, 0, rx);
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_ENABLE);
			#endif
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx_dll_val;
			dll.rxdata_dly = 0;
			dll.rxcmd_dly = rx;
			fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_ENABLE, timing, &dll);

			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = mmc_send_cmd(mmc, &cmd, NULL);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			else{
				printf("########pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
		}
	}

REPORT_RESULT_HS400_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs400_es_rx_cmd_scan, 4, 0, mmc_hs400_es_rx_cmd_scan,
 "scan corrected hs400 ex mode rx cmd delay line settings",
 ""
);

static int mmc_hs400_es_rxdata_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	int rx_cmd_dll_val;
	u32 tx_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	struct mmc_data data = {0};

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;


	if(argc != 3){
		printf("mmc_hs400_rxdata_tuning_scan input parameter err, such as: tx_cmd_dl rx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_cmd_dll_val = simple_strtoul(argv[2], NULL, 16);

	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6 | (1 << 7));
	if (err) {
		printf("switch 8bit ddr err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS400_RX;
			}
			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);

			#if(0)
			phy_dly_setting(p_mshc, tx_dll_val, rx, rx_cmd_dll_val);
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_ENABLE);
			#endif
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx_dll_val;
			dll.rxdata_dly = rx;
			dll.rxcmd_dly = rx_cmd_dll_val;
			fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_ENABLE, timing, &dll);


			cmd.cmdidx = 8;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 0;
			data.dest = (char *)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = MMC_MAX_BLOCK_LEN;
			data.flags = MMC_DATA_READ;

			err = mmc_send_cmd(mmc, &cmd, &data);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				//continue;
			}
			else{
				printf("########pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}

		}
	}

REPORT_RESULT_HS400_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs400_es_rxdata_tuning_scan, 4, 0, mmc_hs400_es_rxdata_tuning_scan,
 "scan corrected hs400 rx data line delay line settings",
 ""
);

static int mmc_hs400_es_txdata_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	int rx_cmd_dll_val;
	u32 rx_dll_val;	
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	struct mmc_data data = {0};

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(argc != 3){
		printf("mmc_hs400_txdata_tuning_scan input parameter err, such as: rx_cmd_dl rx_data_dl\n");
		return CMD_RET_FAILURE;
	}

	rx_cmd_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_dll_val = simple_strtoul(argv[2], NULL, 16);

	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}
	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6 | (1 << 7));
	if (err) {
		printf("switch 8bit ddr err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS400_RX;
			}

			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);
			#if(0)
			phy_dly_setting(p_mshc, tx, rx_dll_val, rx_cmd_dll_val);
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_ENABLE);
			#endif
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx;
			dll.rxdata_dly = rx_dll_val;
			dll.rxcmd_dly = rx_cmd_dll_val;
			fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_ENABLE, timing, &dll);

			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (err){
				printf("write ~~~~~ cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = mmc_send_cmd(mmc, &cmd, &data);
			//mmc_send_status(mmc, 1000);
			if (err){
				printf("read ~~~~ cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
				printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}
		}
	}

REPORT_RESULT_HS400_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs400_es_txdata_tuning_scan, 4, 0, mmc_hs400_es_txdata_tuning_scan,
 "scan corrected hs400 es tx data line delay line settings",
 ""
);

static int mmc_hs400_es_fix_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	
	int rx_cmd_dll_val;

	u32 tx_dll_val;
	u32 rx_dll_val;	
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;


	struct mmc_data data = {0};

	int err;

	if(argc != 4){
		printf("mmc_hs400_fix_test input parameter err, such as: tx_data_dl rx_cmd_dl rx_data_dl\n");
		return CMD_RET_FAILURE;
	}

	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_cmd_dll_val = simple_strtoul(argv[2], NULL, 16);
	rx_dll_val = simple_strtoul(argv[3], NULL, 16);

	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6 | (1 << 7));
	if (err) {
		printf("switch 8bit ddr err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 0x3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);
#if(0)
	phy_dly_setting(p_mshc, tx_dll_val, rx_dll_val, rx_cmd_dll_val);
	fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_ENABLE);
#endif
	struct fh_mshc_phy_dll dll;
	dll.tx_dly = tx_dll_val;
	dll.rxdata_dly = rx_dll_val;
	dll.rxcmd_dly = rx_cmd_dll_val;
	fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_ENABLE, timing, &dll);

	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS400_RX;
			}

			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;

			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}

			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = mmc_send_cmd(mmc, &cmd, &data);
			//mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
				//printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}


		}
	}

REPORT_RESULT_HS400_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs400_es_fix_test, 5, 0, mmc_hs400_es_fix_test,
 "final test hs400 if tuning val correct..",
 ""
);


static int mmc_hs400_classic_rx_cmd_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	u32 tx_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(argc != 2){
		printf("mmc_hs400_rx_cmd_scan input parameter err, such as: tx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}
	tx_dll_val = simple_strtoul(argv[1], NULL, 16);

	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}


	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6);
	if (err) {
		printf("switch 8bit ddr err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;

	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS400_RX;
			}
			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);
			#if(0)
			phy_dly_setting(p_mshc, tx_dll_val, 0, rx);
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
			#endif

			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx_dll_val;
			dll.rxdata_dly = 0;
			dll.rxcmd_dly = rx;
			fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = mmc_send_cmd(mmc, &cmd, NULL);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			else{
				printf("########pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
		}
	}

REPORT_RESULT_HS400_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs400_classic_rx_cmd_scan, 4, 0, mmc_hs400_classic_rx_cmd_scan,
 "scan corrected hs400 classic mode rx cmd delay line settings",
 ""
);


static int mmc_hs400_classic_rxdata_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	int rx_cmd_dll_val;
	u32 tx_dll_val;
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;
	struct mmc_data data = {0};

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;


	if(argc != 3){
		printf("mmc_hs400_rxdata_tuning_scan input parameter err, such as: tx_cmd_dl rx_cmd_dl\n");
		return CMD_RET_FAILURE;
	}

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_cmd_dll_val = simple_strtoul(argv[2], NULL, 16);
	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}


	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6);
	if (err) {
		printf("switch 8bit ddr err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS400_RX;
			}

			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);
			#if(0)
			phy_dly_setting(p_mshc, tx_dll_val, rx, rx_cmd_dll_val);
			fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
			#endif

			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx_dll_val;
			dll.rxdata_dly = rx;
			dll.rxcmd_dly = rx_cmd_dll_val;
			fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

			cmd.cmdidx = 8;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 0;
			data.dest = (char *)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = MMC_MAX_BLOCK_LEN;
			data.flags = MMC_DATA_READ;

			err = mmc_send_cmd(mmc, &cmd, &data);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				//continue;
			}
			else{
				printf("########pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}

		}
	}

REPORT_RESULT_HS400_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs400_classic_rxdata_tuning_scan, 4, 0, mmc_hs400_classic_rxdata_tuning_scan,
 "scan corrected hs400 rx data line delay line settings",
 ""
);

static int mmc_hs400_classic_txdata_tuning_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	
	int rx_cmd_dll_val;
	u32 rx_dll_val;	
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	struct mmc_data data = {0};

	int err;
	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(argc != 3){
		printf("mmc_hs400_txdata_tuning_scan input parameter err, such as: rx_cmd_dl rx_data_dl\n");
		return CMD_RET_FAILURE;
	}

	rx_cmd_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_dll_val = simple_strtoul(argv[2], NULL, 16);

	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}


	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6);
	if (err) {
		printf("switch 8bit ddr err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;
	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS400_RX;
			}

			if(plat_info->soc_ctrl_reset)
				plat_info->soc_ctrl_reset(host);
			mshc_phy_init(p_mshc, INIT_INV_DISABLE);
			fh_mshc_tuning_ctrl_init(host);
			struct fh_mshc_phy_dll dll;
			dll.tx_dly = tx;
			dll.rxdata_dly = rx_dll_val;
			dll.rxcmd_dly = rx_cmd_dll_val;
			fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);
			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = mmc_send_cmd(mmc, &cmd, &data);
			if (err){
				printf("write ~~~~~ cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			err = mmc_send_status(mmc, 1000);
			if (err){
				printf("write ~~~~~ cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}

			printf("#####pass %d : %d\n",tx, rx);
			g_non_ds_ddr[tx][rx] = 1;
			pass_times++;
		}
	}

REPORT_RESULT_HS400_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs400_classic_txdata_tuning_scan, 4, 0, mmc_hs400_classic_txdata_tuning_scan,
 "scan corrected hs400 es tx data line delay line settings",
 ""
);

static int mmc_hs400_classic_fix_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	struct mmc *mmc = 0;
	struct sdhci_host *host;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	int pass_times = 0;
	int fail_times = 0;
	
	int rx_cmd_dll_val;

	u32 tx_dll_val;
	u32 rx_dll_val;	
	struct mmc_cmd cmd;
	u32 tx, rx;
	u32 step_size = 4;
	u32 timing;
	u32 clk;

	struct mmc_data data = {0};

	int err;

	if(argc != 4){
		printf("mmc_hs400_fix_test input parameter err, such as: tx_data_dl rx_cmd_dl rx_data_dl\n");
		return CMD_RET_FAILURE;
	}

	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	host = mmc->priv;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	tx_dll_val = simple_strtoul(argv[1], NULL, 16);
	rx_cmd_dll_val = simple_strtoul(argv[2], NULL, 16);
	rx_dll_val = simple_strtoul(argv[3], NULL, 16);

	err = mmc_tuning_common_init(mmc, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6);
	if (err) {
		printf("switch 8bit ddr err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	
	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 0x3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);
	#if(0)
	phy_dly_setting(p_mshc, tx_dll_val, rx_dll_val, rx_cmd_dll_val);
	fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
	#endif

	struct fh_mshc_phy_dll dll;
	dll.tx_dly = tx_dll_val;
	dll.rxdata_dly = rx_dll_val;
	dll.rxcmd_dly = rx_cmd_dll_val;
	fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

	memset(g_non_ds_ddr, 0, sizeof(g_non_ds_ddr));
	for(tx = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size) {
			if(ctrlc()){
				printf("abort test...\n");
				goto REPORT_RESULT_HS400_RX;
			}
			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;

			err = mmc_send_cmd(mmc, &cmd, &data);
			mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = mmc_send_cmd(mmc, &cmd, &data);
			//mmc_send_status(mmc, 1000);
			if (err){
				printf("!!!!!!cmd err ret is %x %d : %d\n",err,tx,rx);
				fail_times++;
				continue;
			}
			if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
				//printf("#####pass %d : %d\n",tx, rx);
				g_non_ds_ddr[tx][rx] = 1;
				pass_times++;
			}
			else{
				fail_times++;
				printf("!!!!!fail %d : %d\n",tx, rx);
			}
		}
	}

REPORT_RESULT_HS400_RX:
	printf("final pass : fail = %d : %d\n",pass_times, fail_times);
	mmc_printf_dl(g_non_ds_ddr, step_size);

	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_hs400_classic_fix_test, 5, 0, mmc_hs400_classic_fix_test,
 "final test hs400 if tuning val correct..",
 ""
);

static void init_tx_tuning_data(u8* tx_data, u32 tx_size){
	int i;
	u8 *tx_tuning;
	unsigned int random_ret;

	srand(get_timer(0));
	for(i = 0, tx_tuning = (u8*)tx_data; i < tx_size;){
		random_ret = rand();
		//printf("ret random is %x\n",random_ret);
		memcpy(tx_tuning, &random_ret , 4);
		i+= 4;
		tx_tuning += 4;
	}
}

static int mmc_random_fix_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{

	struct mmc *mmc = 0;
	int ret_cnt;
	u32 t_src_addr;
	u32 t_dst_addr;
	u32 t_len;
	u32 t_start_blk;
	u32 t_loop;
	u32 t_cal_blk;
	u32 i;

	if(argc != 6){
		printf("mmc_random_fix_test input parameter err, such as: srcaddr dstaddr len(Byte, for mul 512B) mmc_start_blk loop_times\n");
		return CMD_RET_FAILURE;
	}

	mmc = find_mmc_device(0);
	if(!mmc){
		printf("none mmc handle....\n");
		return -1;
	}
	t_src_addr = simple_strtoul(argv[1], NULL, 16);
	t_dst_addr = simple_strtoul(argv[2], NULL, 16);
	t_len = simple_strtoul(argv[3], NULL, 16);
	t_start_blk = simple_strtoul(argv[4], NULL, 16);
	t_loop = simple_strtoul(argv[5], NULL, 16);

	if(t_len % 512){
		printf("len [%x] should multi for 512B\n",t_len);
		return -1;
	}

	t_cal_blk = t_len / 512;

	for(i = 0; i < t_loop; i++){

		init_tx_tuning_data((u8*)t_src_addr, t_len);
		ret_cnt = blk_dwrite(mmc_get_blk_desc(mmc), t_start_blk, t_cal_blk, (const void *)t_src_addr);
		printf("%d blocks written: %s\n", ret_cnt, (ret_cnt == t_cal_blk) ? "OK" : "ERROR");
		if(ret_cnt != t_cal_blk){
			printf("write err..\n");
			return -1;
		}

		ret_cnt = blk_dread(mmc_get_blk_desc(mmc), t_start_blk, t_cal_blk, (void *)t_dst_addr);
		if(ret_cnt != t_cal_blk){
			printf("read err..\n");
			return -1;
		}
	

		if (memcmp((const void *)t_src_addr, (const void *)t_dst_addr, t_len) == 0){
			printf("##### cmp pass\n");
		}
		else{
			printf("!!!!! cmp fail\n");
			return -1;
		}
	}
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 mmc_random_fix_test, 6, 0, mmc_random_fix_test,
 "final test mmc if tuning val correct..",
 ""
);

/***auto scan***/
#if(0)
static void dump_dl_rec_list(struct rec_dl_info *p_info, int rec_dl_size)
{
	int i = 0;

	for (i = 0; i < rec_dl_size; i++)
		printf("[index 0x%02x] :: tx[%04x] : rx[%04x] = %s\n",i,
		p_info[i].tx_dl, p_info[i].rx_dl, p_info[i].result);
}
#endif
int emmc_parse_dl_rec(struct rec_dl_info *p_info, int rec_dl_size, u32 *p_ret_dl, int tx_or_rx, u32 *p_ret_win_len)
{
	int i;
	int state = STATE_REC_DATA_HI;
	struct rec_dl_info *raw_p_info;
	int best_index;
	int fin_win_hi = INIT_TEST_DATA;
	int fin_win_lo = INIT_TEST_DATA;
	int new_win_hi = INIT_TEST_DATA;
	int new_win_lo = INIT_TEST_DATA;
	raw_p_info = p_info;
	for (i = 0; i < rec_dl_size; i++, p_info++) {

		switch (state) {
		case STATE_REC_DATA_HI:
			if (strcmp(p_info->result, "pass") == 0) {
				//maybe last is pass..
				new_win_hi = i;
				state = STATE_REC_DATA_LO;
			}
		break;
		case STATE_REC_DATA_LO:
			if (strcmp(p_info->result, "pass") != 0) {
				/*if fail, last must be pass*/
				new_win_lo = i - 1;
				state = STATE_REC_DATA_HI;
				/*if new win > old win, just rec max win*/
				if ((new_win_lo - new_win_hi) >=
				(fin_win_lo - fin_win_hi)) {
					fin_win_hi = new_win_hi;
					fin_win_lo = new_win_lo;
				}
			}
		break;
		default:
			printf("unknow state %x\n", state);
			//bugon is better.
			break;
		}
	}
	/*only find one pass...no fail at last..*/
	if ((new_win_hi != INIT_TEST_DATA)  && (new_win_lo == INIT_TEST_DATA)) {
		printf("got one pass, no fail to end..pass index[%d]\n",
		new_win_hi);
		*p_ret_win_len = rec_dl_size - new_win_hi;
		best_index = (rec_dl_size - new_win_hi) / 2;
		best_index += new_win_hi;
		printf("best data index is 0x%x\n", best_index);
		if(tx_or_rx == PARSE_TX_DL_REC)
			*p_ret_dl = raw_p_info[best_index].tx_dl;
		else
			*p_ret_dl = raw_p_info[best_index].rx_dl;

		return 0;
	}

	/*all failed...*/
	if ((new_win_hi == INIT_TEST_DATA)  && (new_win_lo == INIT_TEST_DATA)) {
		//printf("all failed !!!!\n");
		return -1;
	}

	best_index = (fin_win_lo - fin_win_hi + 1) / 2;
	*p_ret_win_len = fin_win_lo - fin_win_hi + 1;
	best_index += fin_win_hi;
	if(tx_or_rx == PARSE_TX_DL_REC)
		*p_ret_dl = raw_p_info[best_index].tx_dl;
	else
		*p_ret_dl = raw_p_info[best_index].rx_dl;
	
	// printf("best win is [0x%x] -> [0x%x]; best data is 0x%x\n",
	// fin_win_hi, fin_win_lo, *p_ret_dl);

	return 0;
}


static void sdhci_tuning_cmd_done(struct sdhci_host *host, struct mmc_cmd *cmd)
{
	int i;
	if (cmd->resp_type & MMC_RSP_136) {
		/* CRC is stripped so we need to do some shifting. */
		for (i = 0; i < 4; i++) {
			cmd->response[i] = sdhci_readl(host,
					SDHCI_RESPONSE + (3-i)*4) << 8;
			if (i != 3)
				cmd->response[i] |= sdhci_readb(host,
						SDHCI_RESPONSE + (3-i)*4-1);
		}
	} else {
		cmd->response[0] = sdhci_readl(host, SDHCI_RESPONSE);
	}
}


static void tuning_sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
{
	int i;
	char *offs;
	for (i = 0; i < data->blocksize; i += 4) {
		offs = data->dest + i;
		if (data->flags == MMC_DATA_READ)
			*(u32 *)offs = sdhci_readl(host, SDHCI_BUFFER);
		else
			sdhci_writel(host, *(u32 *)offs, SDHCI_BUFFER);
	}
}

static int tuning_sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
				unsigned int start_addr)
{
	unsigned int stat, rdy, mask, timeout;

	timeout = 1000000;
	rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
	mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE;
	do {
		stat = sdhci_readl(host, SDHCI_INT_STATUS);
		if (stat & SDHCI_INT_ERROR) {
			// printf("%s: Error detected in status(0x%x)!\n",
			//        __func__, stat);
			return -EIO;
		}
		if (stat & rdy) {
			if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask))
				continue;
			sdhci_writel(host, rdy, SDHCI_INT_STATUS);
			tuning_sdhci_transfer_pio(host, data);
			data->dest += data->blocksize;
		}

		if (timeout-- > 0)
			udelay(10);
		else {
			printf("%s: Transfer data timeout\n", __func__);
			//sdhci_dumpregs(host);
			return -ETIMEDOUT;
		}
	} while (!(stat & SDHCI_INT_DATA_END));
	return 0;
}


static void sdhci_tuning_reset(struct sdhci_host *host, u8 mask)
{

	unsigned long timeout;

	/* Wait max 100 ms */
	timeout = 100;
	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
		if (timeout == 0) {
			printf("%s: Reset 0x%x never completed.\n",
			       __func__, (int)mask);
			return;
		}
		timeout--;
		udelay(1000);
	}

}

static int sdhci_tuning_send_command(struct sdhci_host *host, struct mmc_cmd *cmd,
			      struct mmc_data *data)
{
	unsigned int stat = 0;
	int ret = 0;

	u32 mask, flags, mode;
	unsigned int time = 0, start_addr = 0;

	unsigned start = get_timer(0);
	/* Timeout unit - ms */
	unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT;

	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
	mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;

	/* We shouldn't wait for data inihibit for stop commands, even
	   though they might use busy signaling */
	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
		mask &= ~SDHCI_DATA_INHIBIT;

	while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
		if (time >= cmd_timeout) {
			if (2 * cmd_timeout <= SDHCI_CMD_MAX_TIMEOUT) {
				cmd_timeout += cmd_timeout;
			} else {
				puts("timeout.\n");
				return -ECOMM;
			}
		}
		time++;
		udelay(1000);
	}

	mask = SDHCI_INT_RESPONSE;
	if (!(cmd->resp_type & MMC_RSP_PRESENT))
		flags = SDHCI_CMD_RESP_NONE;
	else if (cmd->resp_type & MMC_RSP_136)
		flags = SDHCI_CMD_RESP_LONG;
	else if (cmd->resp_type & MMC_RSP_BUSY) {
		flags = SDHCI_CMD_RESP_SHORT_BUSY;
		if (data)
			mask |= SDHCI_INT_DATA_END;
	} else
		flags = SDHCI_CMD_RESP_SHORT;

	if (cmd->resp_type & MMC_RSP_CRC)
		flags |= SDHCI_CMD_CRC;
	if (cmd->resp_type & MMC_RSP_OPCODE)
		flags |= SDHCI_CMD_INDEX;
	if (data)
		flags |= SDHCI_CMD_DATA;

	/* Set Transfer mode regarding to data flag */
	if (data != 0) {
		sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
		mode = SDHCI_TRNS_BLK_CNT_EN;

		if (data->blocks > 1)
			mode |= SDHCI_TRNS_MULTI;

		if (data->flags == MMC_DATA_READ)
			mode |= SDHCI_TRNS_READ;


		sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
				data->blocksize),
				SDHCI_BLOCK_SIZE);

#ifdef SDHCI_V4_MODE
		sdhci_writel(host, data->blocks, SDHCI_BLOCK_COUNT);
#else
		sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
#endif
		sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
	} else if (cmd->resp_type & MMC_RSP_BUSY) {
		sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
	}
	sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);

	sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
	start = get_timer(0);
	do {
		stat = sdhci_readl(host, SDHCI_INT_STATUS);
		if (stat & SDHCI_INT_ERROR)
			break;

		if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
			if (host->quirks & SDHCI_QUIRK_BROKEN_R1B) {
				return 0;
			} else {
				printf("%s: Timeout for status update!\n",
				       __func__);
				return -ETIMEDOUT;
			}
		}
	} while ((stat & mask) != mask);

	if ((stat & (SDHCI_INT_ERROR | mask)) == mask) {
		sdhci_tuning_cmd_done(host, cmd);
		sdhci_writel(host, mask, SDHCI_INT_STATUS);
	} else
		ret = -1;

	if (!ret && data)
		ret = tuning_sdhci_transfer_data(host, data, start_addr);

	if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD)
		udelay(1000);

	stat = sdhci_readl(host, SDHCI_INT_STATUS);
	sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS);
	if (!ret) {

		return 0;
	}

	sdhci_tuning_reset(host, SDHCI_RESET_CMD);
	sdhci_tuning_reset(host, SDHCI_RESET_DATA);
	if (stat & SDHCI_INT_TIMEOUT)
		return -ETIMEDOUT;
	else
		return -ECOMM;

}

static int mmc_tuning_send_status(struct sdhci_host *host, int timeout, int mmc_rca)
{
	struct mmc_cmd cmd;
	int err, retries = 5;

	cmd.cmdidx = MMC_CMD_SEND_STATUS;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = mmc_rca << 16;

	while (1) {
		err = sdhci_tuning_send_command(host, &cmd, NULL);
		if (!err) {

			if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR){
					printf("switch err..\n");
					return -EBADMSG;
			}
			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
			     MMC_STATE_PRG)
				break;
			else if (cmd.response[0] & MMC_STATUS_MASK) {
				printf("Status Error: 0x%08X\n",
					cmd.response[0]);
				return -ECOMM;
			}
		} else if (--retries < 0)
			return err;

		if (timeout-- <= 0)
			break;

		udelay(1000);
	}
	if (timeout <= 0) {
		printf("Timeout waiting card ready\n");
		return -ETIMEDOUT;
	}
	return 0;
}



static int sdhci_card_busy(struct sdhci_host *host)
{
    u32 present_state;
	/* Check whether DAT[0] is 0 */
	present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);

	return !(present_state & SDHCI_DATA_0_LVL_MASK);
}

static int _mmc_tuning_switch(struct sdhci_host *host, u8 set,
		u8 index, u8 value, bool send_status)
{

	struct mmc_cmd cmd;
	int timeout = 1000;
	int ret;

	cmd.cmdidx = MMC_CMD_SWITCH;
	cmd.resp_type = MMC_RSP_R1b;
	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
				 (index << 16) |
				 (value << 8) |
				 set;
	ret = sdhci_tuning_send_command(host, &cmd, NULL);

	do {
		if (!sdhci_card_busy(host))
			break;
		udelay(1000);
	} while (--timeout);
	/* Waiting for the ready status */
	timeout = 1000;
	if (!ret && send_status)
		ret = mmc_tuning_send_status(host, timeout, 1);

	return ret;

}


static int mmc_tuning_switch(struct sdhci_host *host, u8 set, u8 index, u8 value)
{
	return _mmc_tuning_switch(host, set, index, value, true);
}


static int mmc_tuning_set_blocklen(struct sdhci_host *host, int len)
{
	struct mmc_cmd cmd;

	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = len;

	return sdhci_tuning_send_command(host, &cmd, NULL);
}

static int mmc_auto_tuning_common_init(struct sdhci_host *host, u8 *p_u8_extdata){
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 timeout = TUING_TIMEOUT;
	struct mmc_data data = {0};

	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	if(!host || !p_mshc || !plat_info){
		printf("err got null info...\n");
		printf("host : p_mshc : plat_info = %x : %x : %x\n",
		(int)host, (int)p_mshc, (int)plat_info);
		return -2;
	}

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_ENABLE);
	fh_mshc_tuning_ctrl_init(host);

	clk = 400000;
	timing = MMC_TIMING_MMC_HS;
	fh_mshc_tuning_set_clock(host, clk, timing, 1, EMMC_ES_MODE_DISABLE);
	cmd.cmdidx =  0;
	cmd.resp_type = MMC_RSP_NONE;
	cmd.cmdarg = 0;
	err = sdhci_tuning_send_command(host, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}

	do{
		cmd.cmdidx = MMC_CMD_SEND_OP_COND;
		cmd.resp_type = MMC_RSP_R3;
		cmd.cmdarg = 0x40000080;
		sdhci_tuning_send_command(host, &cmd, NULL);
		timeout--;
		if(!timeout)
			break;
		udelay(100);
	}while(!(cmd.response[0] & OCR_BUSY));

	if(!timeout){
		printf("try cmd1 timeout\n");
		return -3;
	}

	cmd.cmdidx =  2;
	cmd.resp_type = MMC_RSP_R2;
	cmd.cmdarg = 0;
	err = sdhci_tuning_send_command(host, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}

	//set rel id
	cmd.cmdidx = 3;
	cmd.cmdarg = 1 << 16;
	cmd.resp_type = MMC_RSP_R6;
	err = sdhci_tuning_send_command(host, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}
	/* Get the Card-Specific Data */
	cmd.cmdidx = 9;
	cmd.resp_type = MMC_RSP_R2;
	cmd.cmdarg = 1 << 16;

	err = sdhci_tuning_send_command(host, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}

	//goto sel hs200 mode...
	//sel device..
	cmd.cmdidx = 7;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = 1 << 16;
	err = sdhci_tuning_send_command(host, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}
	//dev is lock? cmd42 to unlock..

	//cmd8 to check if sup hs200..
	cmd.cmdidx = 8;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = 0;
	data.dest = (char *)p_u8_extdata;
	data.blocks = 1;
	data.blocksize = MMC_MAX_BLOCK_LEN;
	data.flags = MMC_DATA_READ;

	err = sdhci_tuning_send_command(host, &cmd, &data);
	if (err){
		printf("!!!!!!raw cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}
	//swtich area....
	p_u8_extdata[EXT_CSD_PART_CONF] &= ~(PART_ACCESS_MASK);
	p_u8_extdata[EXT_CSD_PART_CONF] |= (CONFIG_AUTO_TUNING_EMMC_AREA & PART_ACCESS_MASK);
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_PART_CONF, p_u8_extdata[EXT_CSD_PART_CONF]);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}

	//reread extdata..
	cmd.cmdidx = 8;
	cmd.resp_type = MMC_RSP_R1;
	cmd.cmdarg = 0;
	data.dest = (char *)p_u8_extdata;
	data.blocks = 1;
	data.blocksize = MMC_MAX_BLOCK_LEN;
	data.flags = MMC_DATA_READ;

	err = sdhci_tuning_send_command(host, &cmd, &data);
	if (err){
		printf("!!!!!! fix cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
		return err;
	}

	return 0;
}

int mshc_auto_get_mmc_cid(struct sdhci_host *host, u32 *ret_cid, u8 *emmc_name){

	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	int err;
	u32 timing;
	u32 clk;

	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_ENABLE);
	fh_mshc_tuning_ctrl_init(host);

	clk = 400000;
	timing = MMC_TIMING_MMC_HS;
	fh_mshc_tuning_set_clock(host, clk, timing, 1, EMMC_ES_MODE_DISABLE);
	cmd.cmdidx =  0;
	cmd.resp_type = MMC_RSP_NONE;
	cmd.cmdarg = 0;
	err = sdhci_tuning_send_command(host, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
	}

	do{
		cmd.cmdidx = MMC_CMD_SEND_OP_COND;
		cmd.resp_type = MMC_RSP_R3;
		cmd.cmdarg = 0x40000080;
		sdhci_tuning_send_command(host, &cmd, NULL);
		udelay(100);
	}while(!(cmd.response[0] & OCR_BUSY));


	cmd.cmdidx =  2;
	cmd.resp_type = MMC_RSP_R2;
	cmd.cmdarg = 0;
	err = sdhci_tuning_send_command(host, &cmd, NULL);
	if (err){
		printf("!!!!!!cmd idx[%d] err ret is %x\n",cmd.cmdidx,err);
	}
	//400K cid must be ok~~~
	memcpy(ret_cid, cmd.response, 16);

	translate_mmcid_to_string((char *)emmc_name, cmd.response);
	printf("tuning got emmc_name is %s\n",emmc_name);

	return 0;
}


int mshc_auto_get_mmc_ext(struct sdhci_host *host, u8 *ext_reg){
	int err;

	err = mmc_auto_tuning_common_init(host, ext_reg);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	return 0;
}


int mshc_auto_hs200_rxcmd_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_tx_val, u32 step_size, u32 emmc_init, u32 *ret_cid, u32 tuning_mode){
	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 rx;
	u32 try_times = 0;
	u32 pass_times = 0;


	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = auto_scan_mode_2_clk[tuning_mode];
	timing = MMC_TIMING_MMC_HS200;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

	for(rx = 0, rec_index = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size, rec_index++){
		#if(0)
		phy_dly_setting(p_mshc, init_tx_val, 0, rx);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
		#endif
		struct fh_mshc_phy_dll dll;
		dll.tx_dly = init_tx_val;
		dll.rxdata_dly = 0;
		dll.rxcmd_dly = rx;
		fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);


		try_times = 0;
		pass_times = 0;
		for(; try_times < DLL_TX_RXCMD_PASS_TIMES; try_times++){

			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = sdhci_tuning_send_command(host, &cmd, NULL);
			if (err){
				p_info[rec_index].result = "[rx]::response err";
				break;
			}
			else{
				pass_times++;
			}
		}
		p_info[rec_index].tx_dl = init_tx_val;
		p_info[rec_index].rx_dl = rx;

		if(pass_times == DLL_TX_RXCMD_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}



int mshc_auto_hs_rxcmd_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_tx_val, u32 step_size, u32 emmc_init, u32 *ret_cid, u32 tuning_mode){
	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 rx;
	u32 try_times = 0;
	u32 pass_times = 0;


	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}

	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = auto_scan_mode_2_clk[tuning_mode];
	timing = MMC_TIMING_MMC_HS;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

	for(rx = 0, rec_index = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size, rec_index++){
		struct fh_mshc_phy_dll dll;
		dll.tx_dly = init_tx_val;
		dll.rxdata_dly = 0;
		dll.rxcmd_dly = rx;
		fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;
		for(; try_times < DLL_TX_RXCMD_PASS_TIMES; try_times++){

			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = sdhci_tuning_send_command(host, &cmd, NULL);
			if (err){
				p_info[rec_index].result = "[rx]::response err";
				break;
			}
			else{
				pass_times++;
			}
		}
		p_info[rec_index].tx_dl = init_tx_val;
		p_info[rec_index].rx_dl = rx;

		if(pass_times == DLL_TX_RXCMD_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}



int mshc_auto_hs200_txcmd_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_cmd_val, u32 step_size, u32 emmc_init, u32 *cmp_cid, u32 tuning_mode){
	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 tx;
	u32 try_times = 0;
	u32 pass_times = 0;
	int err;


	if(!host){
		printf("none host handle....\n");
		return -1;
	}
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}


	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = auto_scan_mode_2_clk[tuning_mode];

	//clk = 200000000;
	timing = MMC_TIMING_MMC_HS200;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

	for(tx = 0, rec_index = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size, rec_index++){
		#if(0)
		phy_dly_setting(p_mshc, tx, 0, init_rx_cmd_val);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
		#endif

		struct fh_mshc_phy_dll dll;
		dll.tx_dly = tx;
		dll.rxdata_dly = 0;
		dll.rxcmd_dly = init_rx_cmd_val;
		fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;
		for(; try_times < DLL_TX_RXCMD_PASS_TIMES; try_times++){

			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = sdhci_tuning_send_command(host, &cmd, NULL);
			if (err){
				p_info[rec_index].result = "[tx]::response err";
				break;
			}
			else{
				pass_times++;
			}
		}
		p_info[rec_index].tx_dl = tx;
		p_info[rec_index].rx_dl = init_rx_cmd_val;

		if(pass_times == DLL_TX_RXCMD_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}



int mshc_auto_hs_txcmd_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_cmd_val, u32 step_size, u32 emmc_init, u32 *cmp_cid, u32 tuning_mode){
	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 tx;
	u32 try_times = 0;
	u32 pass_times = 0;
	int err;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}

	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = auto_scan_mode_2_clk[tuning_mode];

	//clk = 200000000;
	timing = MMC_TIMING_MMC_HS;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

	for(tx = 0, rec_index = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size, rec_index++){
		struct fh_mshc_phy_dll dll;
		dll.tx_dly = tx;
		dll.rxdata_dly = 0;
		dll.rxcmd_dly = init_rx_cmd_val;
		fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;
		for(; try_times < DLL_TX_RXCMD_PASS_TIMES; try_times++){

			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = sdhci_tuning_send_command(host, &cmd, NULL);
			if (err){
				p_info[rec_index].result = "[tx]::response err";
				break;
			}
			else{
				pass_times++;
			}
		}
		p_info[rec_index].tx_dl = tx;
		p_info[rec_index].rx_dl = init_rx_cmd_val;

		if(pass_times == DLL_TX_RXCMD_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}

int mshc_auto_hs200_rxdata_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_cmd_val, u32 init_tx_val, u32 step_size, u32 tuning_mode){
	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 rx;
	u32 try_times = 0;
	u32 pass_times = 0;
	struct mmc_data data = {0};	


	int err;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = auto_scan_mode_2_clk[tuning_mode];
	timing = MMC_TIMING_MMC_HS200;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

	for(rx = 0, rec_index = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size, rec_index++){
		#if(0)
		phy_dly_setting(p_mshc, init_tx_val, rx, init_rx_cmd_val);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
		#endif
		struct fh_mshc_phy_dll dll;
		dll.tx_dly = init_tx_val;
		dll.rxdata_dly = rx;
		dll.rxcmd_dly = init_rx_cmd_val;
		fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;

		for(; try_times < DLL_RX_HS200_PASS_TIMES; try_times++){
			cmd.cmdidx = 21;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			//width 8 = 0x80 byte
			data.blocksize = 0x80;
			data.blocks = 1;
			data.flags = MMC_DATA_READ;
			data.dest = (char *)g_hs200_buf;
			memset(g_hs200_buf, 0xff, 0x80);
			err = sdhci_tuning_send_command(host, &cmd, &data);
			if (err){
				p_info[rec_index].result = "[rx]::data err";
				break;
			}

			if (memcmp((char *)g_hs200_buf, tuning_blk_pattern_8bit, 0x80) == 0){
				pass_times++;
			}
			else{
				p_info[rec_index].result = "[rx]::cmp err";
				break;
			}
		}
		p_info[rec_index].tx_dl = init_tx_val;
		p_info[rec_index].rx_dl = rx;

		if(pass_times == DLL_RX_HS200_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}

int mshc_auto_hs_rxdata_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_cmd_val, u32 init_tx_val, u32 step_size, u32 tuning_mode){
	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 rx;
	u32 try_times = 0;
	u32 pass_times = 0;
	struct mmc_data data = {0};	


	int err;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}

	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = auto_scan_mode_2_clk[tuning_mode];
	timing = MMC_TIMING_MMC_HS;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

	for(rx = 0, rec_index = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size, rec_index++){
		#if(0)
		phy_dly_setting(p_mshc, init_tx_val, rx, init_rx_cmd_val);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
		#endif
		struct fh_mshc_phy_dll dll;
		dll.tx_dly = init_tx_val;
		dll.rxdata_dly = rx;
		dll.rxcmd_dly = init_rx_cmd_val;
		fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;

		for(; try_times < DLL_RX_HS200_PASS_TIMES; try_times++){
			cmd.cmdidx = 8;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 0;
			data.dest = (char *)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = MMC_MAX_BLOCK_LEN;
			data.flags = MMC_DATA_READ;

			err = sdhci_tuning_send_command(host, &cmd, &data);
			if (err){
				p_info[rec_index].result = "[rx]::data err";
				break;
			}
			else{
				pass_times++;
			}

		}
		p_info[rec_index].tx_dl = init_tx_val;
		p_info[rec_index].rx_dl = rx;

		if(pass_times == DLL_RX_HS200_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}

int mshc_hs200_auto_fix_test(struct sdhci_host *host, u32 init_tx_val,
u32 init_rx_cmd_val, u32 init_rx_val, u32 test_times, u32 tuning_mode){
	int i;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	struct mmc_data data = {0};	

	int err;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;


	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	err = mmc_tuning_set_blocklen(host, 512);
	if (err) {
		printf("mmc_tuning_set_blocklen err, err:%d\n", err);
		return err;
	}

	//switch ctrl width and timing
	clk = auto_scan_mode_2_clk[tuning_mode];
	timing = MMC_TIMING_MMC_HS200;
	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);
#if(0)
	phy_dly_setting(p_mshc, init_tx_val, init_rx_val, init_rx_cmd_val);
	fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
#endif

	struct fh_mshc_phy_dll dll;
	dll.tx_dly = init_tx_val;
	dll.rxdata_dly = init_rx_val;
	dll.rxcmd_dly = init_rx_cmd_val;
	fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

	//printf("CONFIG_AUTO_TUNING_EMMC_ADDR add is %x\n",CONFIG_AUTO_TUNING_EMMC_ADDR);
	for(i = 0; i < test_times; i++){

		init_tx_tuning_data(g_mshc_ext_data, 512);
		//write
		cmd.cmdidx = 24;
		cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
		cmd.resp_type = MMC_RSP_R1;
		data.src = (const char*)g_mshc_ext_data;
		data.blocks = 1;
		data.blocksize = 512;
		data.flags = MMC_DATA_WRITE;
		err = sdhci_tuning_send_command(host, &cmd, &data);
		if(err){
			printf("write err...\n");
			return -1;
		}
		err = mmc_tuning_send_status(host, 1000, 1);
		if(err){
			printf("write read status err...\n");
			return -1;
		}
		//read
		cmd.cmdidx = 17;
		cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
		cmd.resp_type = MMC_RSP_R1;
		data.dest = (char *)g_cmp_csd;
		data.blocks = 1;
		data.blocksize = 512;
		data.flags = MMC_DATA_READ;
		err = sdhci_tuning_send_command(host, &cmd, &data);
		if(err){
			printf("read err...\n");
			return -1;
		}
		err = mmc_tuning_send_status(host, 1000, 1);
		if(err){
			printf("read read status err...\n");
			return -1;
		}
		if (memcmp(g_cmp_csd, g_mshc_ext_data, 512) == 0){

		}
		else{
			return -1;
		}
	}

	return 0;
}



int mshc_hs_auto_fix_test(struct sdhci_host *host, u32 init_tx_val,
u32 init_rx_cmd_val, u32 init_rx_val, u32 test_times, u32 tuning_mode){
	int i;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	struct mmc_data data = {0};	

	int err;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;


	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}

	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	err = mmc_tuning_set_blocklen(host, 512);
	if (err) {
		printf("mmc_tuning_set_blocklen err, err:%d\n", err);
		return err;
	}

	//switch ctrl width and timing
	clk = auto_scan_mode_2_clk[tuning_mode];
	timing = MMC_TIMING_MMC_HS;
	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);
#if(0)
	phy_dly_setting(p_mshc, init_tx_val, init_rx_val, init_rx_cmd_val);
	fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
#endif

	struct fh_mshc_phy_dll dll;
	dll.tx_dly = init_tx_val;
	dll.rxdata_dly = init_rx_val;
	dll.rxcmd_dly = init_rx_cmd_val;
	fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

	//printf("CONFIG_AUTO_TUNING_EMMC_ADDR add is %x\n",CONFIG_AUTO_TUNING_EMMC_ADDR);
	for(i = 0; i < test_times; i++){

		init_tx_tuning_data(g_mshc_ext_data, 512);
		//write
		cmd.cmdidx = 24;
		cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
		cmd.resp_type = MMC_RSP_R1;
		data.src = (const char*)g_mshc_ext_data;
		data.blocks = 1;
		data.blocksize = 512;
		data.flags = MMC_DATA_WRITE;
		err = sdhci_tuning_send_command(host, &cmd, &data);
		if(err){
			printf("write err...\n");
			return -1;
		}
		err = mmc_tuning_send_status(host, 1000, 1);
		if(err){
			printf("write read status err...\n");
			return -1;
		}
		//read
		cmd.cmdidx = 17;
		cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
		cmd.resp_type = MMC_RSP_R1;
		data.dest = (char *)g_cmp_csd;
		data.blocks = 1;
		data.blocksize = 512;
		data.flags = MMC_DATA_READ;
		err = sdhci_tuning_send_command(host, &cmd, &data);
		if(err){
			printf("read err...\n");
			return -1;
		}
		err = mmc_tuning_send_status(host, 1000, 1);
		if(err){
			printf("read read status err...\n");
			return -1;
		}
		if (memcmp(g_cmp_csd, g_mshc_ext_data, 512) == 0){

		}
		else{
			return -1;
		}
	}

	return 0;
}


int mshc_hs200_auto_classic_tuning(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_val, u32 step_size, u32 tuning_mode){

	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 tx;
	u32 try_times = 0;
	u32 pass_times = 0;
	int err;
	struct mmc_data data = {0};

	if(!host){
		printf("none host handle....\n");
		return -1;
	}
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	for(tx = 0, rec_index = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size, rec_index++){
		if(plat_info->soc_clk_init)
			plat_info->soc_clk_init(host);
		fh_mshc_lite_hw_reset(p_mshc);
		err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
		if(err){
			printf("mmc common init err..%x\n",err);
			return err;
		}
		//set width 8 bit
		err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
			EXT_CSD_BUS_WIDTH, 2);
		if (err) {
			printf("switch width err, err:%d\n", err);
			return err;
		}
		//set hs200 timing and driver strength 0
		err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
		if (err) {
			printf("switch timing err, err:%d\n", err);
			return err;
		}

		err = mmc_tuning_set_blocklen(host, 512);
		if (err) {
			printf("mmc_tuning_set_blocklen err, err:%d\n", err);
			return err;
		}

		clk = auto_scan_mode_2_clk[tuning_mode];

		timing = MMC_TIMING_MMC_HS200;
		if(plat_info->soc_ctrl_reset)
			plat_info->soc_ctrl_reset(host);
		mshc_phy_init(p_mshc, INIT_INV_DISABLE);
		fh_mshc_tuning_ctrl_init(host);
		#if(0)
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
		phy_dly_setting(p_mshc, tx, init_rx_val, init_rx_val);
		#endif
		struct fh_mshc_phy_dll dll;
		dll.tx_dly = tx;
		dll.rxdata_dly = init_rx_val;
		dll.rxcmd_dly = init_rx_val;
		fh_mshc_hs200_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;
		for(; try_times < DLL_TX_RXCMD_PASS_TIMES; try_times++){

			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = sdhci_tuning_send_command(host, &cmd, &data);
			if (err){
				p_info[rec_index].result = "[tx]::write err";
				break;
			}
			err = mmc_tuning_send_status(host, 1000, 1);
			if(err){
				p_info[rec_index].result = "[tx]::w_status err";
				break;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = sdhci_tuning_send_command(host, &cmd, &data);
			if(err){
				p_info[rec_index].result = "[rx]::read err";
				break;
			}
			err = mmc_tuning_send_status(host, 1000, 1);
			if(err){
				p_info[rec_index].result = "[rx]::r_status err";
				break;
			}
			if (memcmp(g_cmp_csd, g_mshc_ext_data, 512) == 0){
				pass_times++;
			}
			else{
				p_info[rec_index].result = "[cmp]::err";
				break;
			}

		}
		p_info[rec_index].tx_dl = tx;
		p_info[rec_index].rx_dl = init_rx_val;

		if(pass_times == DLL_TX_RXCMD_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;

}



int mshc_hs_auto_classic_tuning(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_val, u32 step_size, u32 tuning_mode){

	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 tx;
	u32 try_times = 0;
	u32 pass_times = 0;
	int err;
	struct mmc_data data = {0};

	if(!host){
		printf("none host handle....\n");
		return -1;
	}
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	for(tx = 0, rec_index = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size, rec_index++){
		if(plat_info->soc_clk_init)
			plat_info->soc_clk_init(host);
		fh_mshc_lite_hw_reset(p_mshc);
		err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
		if(err){
			printf("mmc common init err..%x\n",err);
			return err;
		}
		//set width 8 bit
		err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
			EXT_CSD_BUS_WIDTH, 2);
		if (err) {
			printf("switch width err, err:%d\n", err);
			return err;
		}
		//set hs200 timing and driver strength 0
		err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
		if (err) {
			printf("switch timing err, err:%d\n", err);
			return err;
		}

		err = mmc_tuning_set_blocklen(host, 512);
		if (err) {
			printf("mmc_tuning_set_blocklen err, err:%d\n", err);
			return err;
		}

		clk = auto_scan_mode_2_clk[tuning_mode];

		timing = MMC_TIMING_MMC_HS;
		if(plat_info->soc_ctrl_reset)
			plat_info->soc_ctrl_reset(host);
		mshc_phy_init(p_mshc, INIT_INV_DISABLE);
		fh_mshc_tuning_ctrl_init(host);
		#if(0)
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
		phy_dly_setting(p_mshc, tx, init_rx_val, init_rx_val);
		#endif
		struct fh_mshc_phy_dll dll;
		dll.tx_dly = tx;
		dll.rxdata_dly = init_rx_val;
		dll.rxcmd_dly = init_rx_val;
		fh_mshc_hs_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;
		for(; try_times < DLL_HS_CLASSIC_PASS_TIMES; try_times++){

			init_tx_tuning_data(g_mshc_ext_data, 512);
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = sdhci_tuning_send_command(host, &cmd, &data);
			if (err){
				p_info[rec_index].result = "[tx]::write err";
				break;
			}
			err = mmc_tuning_send_status(host, 1000, 1);
			if(err){
				p_info[rec_index].result = "[tx]::w_status err";
				break;
			}
			//read
			cmd.cmdidx = 17;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.dest = (char *)g_cmp_csd;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_READ;
			err = sdhci_tuning_send_command(host, &cmd, &data);
			if(err){
				p_info[rec_index].result = "[rx]::read err";
				break;
			}
			err = mmc_tuning_send_status(host, 1000, 1);
			if(err){
				p_info[rec_index].result = "[rx]::r_status err";
				break;
			}
			if (memcmp(g_cmp_csd, g_mshc_ext_data, 512) == 0){
				pass_times++;
			}
			else{
				p_info[rec_index].result = "[cmp]::err";
				break;
			}

		}
		p_info[rec_index].tx_dl = tx;
		p_info[rec_index].rx_dl = init_rx_val;

		if(pass_times == DLL_HS_CLASSIC_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;

}

int mshc_auto_get_emmc_tuning_data(struct sdhci_host *host, u8 *buf){
	struct mmc_cmd cmd;
	struct mmc_data data = {0};
	int err;

	err = mmc_auto_tuning_common_init(host, buf);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 0);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	err = mmc_tuning_set_blocklen(host, 512);
	if (err) {
		printf("mmc_tuning_set_blocklen err, err:%d\n", err);
		return err;
	}

	//read
	cmd.cmdidx = 17;
	cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
	cmd.resp_type = MMC_RSP_R1;
	data.dest = (char *)buf;
	data.blocks = 1;
	data.blocksize = 512;
	data.flags = MMC_DATA_READ;
	err = sdhci_tuning_send_command(host, &cmd, &data);
	if(err){
		printf("read err...\n");
		return -1;
	}
	return 0;
}

int mshc_auto_write_emmc_tuning_data(struct sdhci_host *host, u8 *buf){
	struct mmc_cmd cmd;
	struct mmc_data data = {0};
	int err;

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL,
		EXT_CSD_BUS_WIDTH, 0);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	err = mmc_tuning_set_blocklen(host, 512);
	if (err) {
		printf("mmc_tuning_set_blocklen err, err:%d\n", err);
		return err;
	}

	cmd.cmdidx = 24;
	cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
	cmd.resp_type = MMC_RSP_R1;
	data.src = (const char*)buf;
	data.blocks = 1;
	data.blocksize = 512;
	data.flags = MMC_DATA_WRITE;
	err = sdhci_tuning_send_command(host, &cmd, &data);
	if(err){
		printf("write err...\n");
		return -1;
	}
	err = mmc_tuning_send_status(host, 1000, 1);
	if(err){
		printf("write read status err...\n");
		return -1;
	}
	return 0;
}

int mshc_auto_hs400_es_rxcmd_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_tx_val, u32 step_size, u32 *ret_cid){
	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 rx;
	u32 try_times = 0;
	u32 pass_times = 0;


	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;


	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}
	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6 | (1 << 7));
	if (err) {
		printf("switch 8bit ddr and es err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}
	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;
	for(rx = 0, rec_index = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size, rec_index++){

		if(plat_info->soc_ctrl_reset)
			plat_info->soc_ctrl_reset(host);
		mshc_phy_init(p_mshc, INIT_INV_DISABLE);
		fh_mshc_tuning_ctrl_init(host);
		#if(0)
		phy_dly_setting(p_mshc, init_tx_val, 0, rx);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_ENABLE);
		#endif

		struct fh_mshc_phy_dll dll;
		dll.tx_dly = init_tx_val;
		dll.rxdata_dly = 0;
		dll.rxcmd_dly = rx;
		fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_ENABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;
		for(; try_times < DLL_TX_RXCMD_PASS_TIMES; try_times++){

			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = sdhci_tuning_send_command(host, &cmd, NULL);

			if (err){
				p_info[rec_index].result = "[rx]::response err";
				break;
			}
			else{
				pass_times++;
			}
		}
		p_info[rec_index].tx_dl = init_tx_val;
		p_info[rec_index].rx_dl = rx;

		if(pass_times == DLL_TX_RXCMD_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}

int mshc_auto_hs400_es_rxdata_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_cmd_val, u32 init_tx_val, u32 step_size){

	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 rx;
	u32 try_times = 0;
	u32 pass_times = 0;
	struct mmc_data data = {0};


	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;


	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}
	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6 | (1 << 7));
	if (err) {
		printf("switch 8bit ddr and es err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;

	for(rx = 0, rec_index = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size, rec_index++){
		if(plat_info->soc_ctrl_reset)
			plat_info->soc_ctrl_reset(host);
		mshc_phy_init(p_mshc, INIT_INV_DISABLE);
		fh_mshc_tuning_ctrl_init(host);
		#if(0)
		phy_dly_setting(p_mshc, init_tx_val, rx, init_rx_cmd_val);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_ENABLE);
		#endif

		struct fh_mshc_phy_dll dll;
		dll.tx_dly = init_tx_val;
		dll.rxdata_dly = rx;
		dll.rxcmd_dly = init_rx_cmd_val;
		fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_ENABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;

		for(; try_times < DLL_RX_HS400_PASS_TIMES; try_times++){
			cmd.cmdidx = 8;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 0;
			data.dest = (char *)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = MMC_MAX_BLOCK_LEN;
			data.flags = MMC_DATA_READ;
			err = sdhci_tuning_send_command(host, &cmd, &data);
			if (err){
				p_info[rec_index].result = "[rx]::data err";
				break;
			}
			else
				pass_times++;
		}
		p_info[rec_index].tx_dl = init_tx_val;
		p_info[rec_index].rx_dl = rx;

		if(pass_times == DLL_RX_HS400_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}

int mshc_auto_hs400_es_txdata_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_cmd_val, u32 init_rx_data_val, u32 step_size){

	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 tx;
	u32 try_times = 0;
	u32 pass_times = 0;
	struct mmc_data data = {0};

	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}
	//some emmc may err.when tx clk dll change...so do init... 
	for(tx = 0, rec_index = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size, rec_index++){

		err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
		if(err){
			printf("mmc common init err..%x\n",err);
			return err;
		}
		//set width 8 bit
		err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
		if (err) {
			printf("switch width err, err:%d\n", err);
			return err;
		}
		//set hs200 timing and driver strength 0
		err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
		if (err) {
			printf("switch timing err, err:%d\n", err);
			return err;
		}
		//hs400 pass hs200 tuning process
		//set high speed mode
		err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
		if (err) {
			printf("switch hs speed timing err, err:%d\n", err);
			return err;
		}
		//set ddr8bit mode
		err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6 | (1 << 7));
		if (err) {
			printf("switch 8bit ddr and es err, err:%d\n", err);
			return err;
		}
		//set timing hs400
		err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
		if (err) {
			printf("switch hs400 timing err, err:%d\n", err);
			return err;
		}

		//switch ctrl width and timing
		clk = 200000000;
		timing = MMC_TIMING_MMC_HS400;
		if(plat_info->soc_ctrl_reset)
			plat_info->soc_ctrl_reset(host);
		mshc_phy_init(p_mshc, INIT_INV_DISABLE);
		fh_mshc_tuning_ctrl_init(host);
		#if(0)
		phy_dly_setting(p_mshc, tx, init_rx_data_val, init_rx_cmd_val);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_ENABLE);
		#endif
		struct fh_mshc_phy_dll dll;
		dll.tx_dly = tx;
		dll.rxdata_dly = init_rx_data_val;
		dll.rxcmd_dly = init_rx_cmd_val;
		fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_ENABLE, timing, &dll);


		init_tx_tuning_data(g_mshc_ext_data, 512);
		try_times = 0;
		pass_times = 0;

		for(; try_times < DLL_TX_HS400_PASS_TIMES; try_times++){
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = sdhci_tuning_send_command(host, &cmd, &data);
			if(err){
				p_info[rec_index].result = "[tx]::wirte err";
				break;
			}
			err = mmc_tuning_send_status(host, 1000, 1);
			if(err){
				p_info[rec_index].result = "[tx]::w_status err";
				break;
			}
			pass_times++;
		}
		p_info[rec_index].tx_dl = tx;
		p_info[rec_index].rx_dl = init_rx_data_val;

		if(pass_times == DLL_TX_HS400_PASS_TIMES){

			p_info[rec_index].result = "pass";
		}

	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}

int mshc_auto_hs400_es_fix_test(struct sdhci_host *host, u32 init_tx_val,
u32 init_rx_cmd_val, u32 init_rx_val, u32 test_times){
	int i;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	struct mmc_data data = {0};


	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6 | (1 << 7));
	if (err) {
		printf("switch 8bit ddr and es err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;
	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);

#if(0)
	phy_dly_setting(p_mshc, init_tx_val, init_rx_val, init_rx_cmd_val);
	fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_ENABLE);
#endif

	struct fh_mshc_phy_dll dll;
	dll.tx_dly = init_tx_val;
	dll.rxdata_dly = init_rx_val;
	dll.rxcmd_dly = init_rx_cmd_val;
	fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_ENABLE, timing, &dll);

	for(i = 0; i < test_times; i++){

		init_tx_tuning_data(g_mshc_ext_data, 512);
		//write
		cmd.cmdidx = 24;
		cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
		cmd.resp_type = MMC_RSP_R1;
		data.src = (const char*)g_mshc_ext_data;
		data.blocks = 1;
		data.blocksize = 512;
		data.flags = MMC_DATA_WRITE;
		err = sdhci_tuning_send_command(host, &cmd, &data);
		if(err){
			printf("write err...\n");
			return -1;
		}
		err = mmc_tuning_send_status(host, 1000, 1);
		if(err){
			printf("write read status err...\n");
			return -1;
		}

		//read
		cmd.cmdidx = 17;
		cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
		cmd.resp_type = MMC_RSP_R1;
		data.dest = (char *)g_cmp_csd;
		data.blocks = 1;
		data.blocksize = 512;
		data.flags = MMC_DATA_READ;
		err = sdhci_tuning_send_command(host, &cmd, &data);
		if(err){
			printf("read err...\n");
			return -1;
		}
		err = mmc_tuning_send_status(host, 1000, 1);
		if(err){
			printf("read read status err...\n");
			return -1;
		}
		if (memcmp(g_cmp_csd, g_mshc_ext_data, 512) == 0){
			
		}
		else{
			printf("!!!!!fail\n");
			return -1;
		}
	}
	return 0;
}

int mshc_auto_hs400_classic_rxdata_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_cmd_val, u32 init_tx_val, u32 step_size){

	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 rx;
	u32 try_times = 0;
	u32 pass_times = 0;
	struct mmc_data data = {0};

	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;


	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//printf("device type is [%x]\n",p_u8[196]);
	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}

	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6);
	if (err) {
		printf("switch 8bit ddr and es err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;

	for(rx = 0, rec_index = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size, rec_index++){
		if(plat_info->soc_ctrl_reset)
			plat_info->soc_ctrl_reset(host);
		mshc_phy_init(p_mshc, INIT_INV_DISABLE);
		fh_mshc_tuning_ctrl_init(host);
		#if(0)
		phy_dly_setting(p_mshc, init_tx_val, rx, init_rx_cmd_val);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
		#endif

		struct fh_mshc_phy_dll dll;
		dll.tx_dly = init_tx_val;
		dll.rxdata_dly = rx;
		dll.rxcmd_dly = init_rx_cmd_val;
		fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;

		for(; try_times < DLL_RX_HS400_PASS_TIMES; try_times++){
			cmd.cmdidx = 8;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 0;
			data.dest = (char *)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = MMC_MAX_BLOCK_LEN;
			data.flags = MMC_DATA_READ;
			err = sdhci_tuning_send_command(host, &cmd, &data);
			if (err){
				p_info[rec_index].result = "[rx]::data err";
				break;
			}
			else
				pass_times++;
		}
		p_info[rec_index].tx_dl = init_tx_val;
		p_info[rec_index].rx_dl = rx;

		if(pass_times == DLL_RX_HS400_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}

int mshc_auto_hs400_classic_txdata_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_rx_cmd_val, u32 init_rx_data_val, u32 step_size){
	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 tx;
	u32 try_times = 0;
	u32 pass_times = 0;
	struct mmc_data data = {0};
	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;


	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6);
	if (err) {
		printf("switch 8bit ddr and es err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;

	for(tx = 0, rec_index = 0; tx < MAX_TX_DELAY_LINE_SIZE; tx += step_size, rec_index++){

		if(plat_info->soc_ctrl_reset)
			plat_info->soc_ctrl_reset(host);
		mshc_phy_init(p_mshc, INIT_INV_DISABLE);
		fh_mshc_tuning_ctrl_init(host);
		#if(0)
		phy_dly_setting(p_mshc, tx, init_rx_data_val, init_rx_cmd_val);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
		#endif

		struct fh_mshc_phy_dll dll;
		dll.tx_dly = tx;
		dll.rxdata_dly = init_rx_data_val;
		dll.rxcmd_dly = init_rx_cmd_val;
		fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);


		init_tx_tuning_data(g_mshc_ext_data, 512);
		try_times = 0;
		pass_times = 0;

		for(; try_times < DLL_TX_HS400_PASS_TIMES; try_times++){
			//write
			cmd.cmdidx = 24;
			cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
			cmd.resp_type = MMC_RSP_R1;
			data.src = (const char*)g_mshc_ext_data;
			data.blocks = 1;
			data.blocksize = 512;
			data.flags = MMC_DATA_WRITE;
			err = sdhci_tuning_send_command(host, &cmd, &data);
			if(err){
				p_info[rec_index].result = "[tx]::wirte err";
				break;
			}
			err = mmc_tuning_send_status(host, 1000, 1);
			if(err){
				p_info[rec_index].result = "[tx]::w_status err";
				break;
			}
			pass_times++;
		}
		p_info[rec_index].tx_dl = tx;
		p_info[rec_index].rx_dl = init_rx_data_val;

		if(pass_times == DLL_TX_HS400_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_rx_data_val, tx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}

int mshc_auto_hs400_classic_fix_test(struct sdhci_host *host, u32 init_tx_val,
u32 init_rx_cmd_val, u32 init_rx_val, u32 test_times){
	int i;

	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	struct mmc_data data = {0};


	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;

	if(!host){
		printf("none host handle....\n");
		return -1;
	}
	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}
	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6);
	if (err) {
		printf("switch 8bit ddr and es err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;

	if(plat_info->soc_ctrl_reset)
		plat_info->soc_ctrl_reset(host);
	mshc_phy_init(p_mshc, INIT_INV_DISABLE);
	fh_mshc_tuning_ctrl_init(host);
#if(0)
	phy_dly_setting(p_mshc, init_tx_val, init_rx_val, init_rx_cmd_val);
	fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
#endif

	struct fh_mshc_phy_dll dll;
	dll.tx_dly = init_tx_val;
	dll.rxdata_dly = init_rx_val;
	dll.rxcmd_dly = init_rx_cmd_val;
	fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

	for(i = 0; i < test_times; i++){

		init_tx_tuning_data(g_mshc_ext_data, 512);
		//write
		cmd.cmdidx = 24;
		cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
		cmd.resp_type = MMC_RSP_R1;
		data.src = (const char*)g_mshc_ext_data;
		data.blocks = 1;
		data.blocksize = 512;
		data.flags = MMC_DATA_WRITE;
		err = sdhci_tuning_send_command(host, &cmd, &data);
		if(err){
			printf("write err...\n");
			return -1;
		}
		err = mmc_tuning_send_status(host, 1000, 1);
		if(err){
			printf("write read status err...\n");
			return -1;
		}

		//read
		cmd.cmdidx = 17;
		cmd.cmdarg = CONFIG_AUTO_TUNING_EMMC_ADDR;
		cmd.resp_type = MMC_RSP_R1;
		data.dest = (char *)g_cmp_csd;
		data.blocks = 1;
		data.blocksize = 512;
		data.flags = MMC_DATA_READ;
		err = sdhci_tuning_send_command(host, &cmd, &data);
		if(err){
			printf("read err...\n");
			return -1;
		}
		err = mmc_tuning_send_status(host, 1000, 1);
		if(err){
			printf("read read status err...\n");
			return -1;
		}
		if (memcmp((const void *)g_cmp_csd, (const void *)g_mshc_ext_data, 512) == 0){
			
		}
		else{
			printf("!!!!!fail\n");
			return -1;
		}
	}
	return 0;
}

int mshc_auto_hs400_classic_rxcmd_dl_rec(struct sdhci_host *host, struct rec_dl_info *p_info, int rec_dl_size,
u32 init_tx_val, u32 step_size, u32 *ret_cid){

	int rec_index;
	struct fh_mshc_lite *p_mshc;
	struct mshc_lite_plat_info *plat_info;
	struct mmc_cmd cmd;
	u32 timing;
	u32 clk;
	u32 rx;
	u32 try_times = 0;
	u32 pass_times = 0;

	int err;
	p_mshc = host->dri_pri;
	plat_info = p_mshc->plat;


	if(!host){
		printf("none host handle....\n");
		return -1;
	}

	for (rec_index = 0; rec_index < rec_dl_size; rec_index++) {
		memset(&p_info[rec_index], 0, sizeof(struct rec_dl_info));
		p_info[rec_index].result = "fail";
	}

	err = mmc_auto_tuning_common_init(host, g_mshc_ext_data);
	if(err){
		printf("mmc common init err..%x\n",err);
		return err;
	}

	//set width 8 bit
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 2);
	if (err) {
		printf("switch width err, err:%d\n", err);
		return err;
	}
	//set hs200 timing and driver strength 0
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 2);
	if (err) {
		printf("switch timing err, err:%d\n", err);
		return err;
	}


	//hs400 pass hs200 tuning process
	//set high speed mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
	if (err) {
		printf("switch hs speed timing err, err:%d\n", err);
		return err;
	}
	//set ddr8bit mode
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 6);
	if (err) {
		printf("switch 8bit ddr and es err, err:%d\n", err);
		return err;
	}
	//set timing hs400
	err = mmc_tuning_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 3);
	if (err) {
		printf("switch hs400 timing err, err:%d\n", err);
		return err;
	}

	//switch ctrl width and timing
	clk = 200000000;
	timing = MMC_TIMING_MMC_HS400;

	for(rx = 0, rec_index = 0; rx < MAX_RX_DELAY_LINE_SIZE; rx += step_size, rec_index++){
		if(plat_info->soc_ctrl_reset)
			plat_info->soc_ctrl_reset(host);
		mshc_phy_init(p_mshc, INIT_INV_DISABLE);
		fh_mshc_tuning_ctrl_init(host);
		#if(0)
		phy_dly_setting(p_mshc, init_tx_val, 0, rx);
		fh_mshc_tuning_set_clock(host, clk, timing, 8, EMMC_ES_MODE_DISABLE);
		#endif

		struct fh_mshc_phy_dll dll;
		dll.tx_dly = init_tx_val;
		dll.rxdata_dly = 0;
		dll.rxcmd_dly = rx;
		fh_mshc_hs400_setting(host, clk, 8, EMMC_ES_MODE_DISABLE, timing, &dll);

		try_times = 0;
		pass_times = 0;
		for(; try_times < DLL_TX_RXCMD_PASS_TIMES; try_times++){


			cmd.cmdidx = MMC_CMD_SEND_STATUS;
			cmd.resp_type = MMC_RSP_R1;
			cmd.cmdarg = 1 << 16;
			err = sdhci_tuning_send_command(host, &cmd, NULL);

			if (err){
				p_info[rec_index].result = "[rx]::response err";
				break;
			}
			else{
				pass_times++;
			}
		}
		p_info[rec_index].tx_dl = init_tx_val;
		p_info[rec_index].rx_dl = rx;

		if(pass_times == DLL_TX_RXCMD_PASS_TIMES){
			//printf("got %d good ##############pass %d : %d\n",DLL_TX_RXCMD_PASS_TIMES, init_tx_val, rx);
			p_info[rec_index].result = "pass";
		}
	}
	//dump_dl_rec_list(p_info, rec_dl_size);
	return 0;
}
